package com.mhz.cae.util;

import org.anddev.andengine.extension.input.touch.controller.MultiTouch;
import org.anddev.andengine.extension.input.touch.exception.MultiTouchException;
import org.anddev.andengine.input.touch.TouchEvent;
import org.anddev.andengine.input.touch.detector.BaseDetector;

import android.util.FloatMath;
import android.view.MotionEvent;

/** MultiTouchDetector */
public class MultiTouchDetector extends BaseDetector {

	/** Multitouch listener */
	private final IMultiTouchDetectorListener mMultiTouchDetectorListener;

	// Variable to calculate distance
	private float mInitialDistance;
	private float mCurrentDistance;

	// Variable to calculate angle
	private float mInitialAngle;
	private float mCurrentAngle;
	private boolean mRotating;

	public MultiTouchDetector(final IMultiTouchDetectorListener pMultiTouchDetectorListener) throws MultiTouchException {
		if (MultiTouch.isSupportedByAndroidVersion() == false) {
			throw new MultiTouchException();
		}
		this.mMultiTouchDetectorListener = pMultiTouchDetectorListener;
	}

	@Override
	public boolean onManagedTouchEvent(final TouchEvent pSceneTouchEvent) {
		final MotionEvent motionEvent = pSceneTouchEvent.getMotionEvent();
		final int action = motionEvent.getAction() & MotionEvent.ACTION_MASK;

		switch (action) {
		case MotionEvent.ACTION_POINTER_DOWN:
			if (!this.mRotating) {
				this.mInitialDistance = this.calculatePointerDistance(motionEvent);
				this.mInitialAngle = MultiTouchDetector.calculateRadialAngle(motionEvent);
				this.mRotating = true;
				this.mMultiTouchDetectorListener.onTouchStarted(this, pSceneTouchEvent);
			}
			break;
		case MotionEvent.ACTION_UP:
		case MotionEvent.ACTION_POINTER_UP:
			if (this.mRotating) {
				this.mRotating = false;
				this.mMultiTouchDetectorListener.onTouchFinished(this, pSceneTouchEvent, this.getZoomFactor(), this.getAngle());
			}
			break;
		case MotionEvent.ACTION_MOVE:
			if (this.mRotating) {
				this.mCurrentDistance = this.calculatePointerDistance(motionEvent);
				this.mCurrentAngle = MultiTouchDetector.calculateRadialAngle(motionEvent);
				this.mMultiTouchDetectorListener.onTouchMotion(this, pSceneTouchEvent, this.getZoomFactor(), this.getAngle());
			}
			break;
		}
		return true;
	}

	/** Return the zoom factor */
	private float getZoomFactor() {
		return this.mCurrentDistance / this.mInitialDistance;
	}

	/** Return radial angle */
	private float getAngle() {
		return (this.mCurrentAngle - this.mInitialAngle);
	}

	/** Calculate the euclidian distance between the first two fingers. */
	private float calculatePointerDistance(final MotionEvent pMotionEvent) {
		final float x = pMotionEvent.getX(0) - pMotionEvent.getX(1);
		final float y = pMotionEvent.getY(0) - pMotionEvent.getY(1);
		return FloatMath.sqrt(x * x + y * y);
	}

	/** Calculate the radial angle */
	private static float calculateRadialAngle(final MotionEvent pMotionEvent) {
		return (float) Math.atan2(pMotionEvent.getY(1) - pMotionEvent.getY(0), pMotionEvent.getX(1) - pMotionEvent.getX(0));
	}

	/** MultiTouchListener */
	public static interface IMultiTouchDetectorListener {

		public void onTouchStarted(final MultiTouchDetector pRotateDetector, final TouchEvent pSceneTouchEvent);

		public void onTouchMotion(final MultiTouchDetector pRotateDetector, final TouchEvent pTouchEvent, final float pZoomFactor, final float pAngle);

		public void onTouchFinished(final MultiTouchDetector pRotateDetector, final TouchEvent pTouchEvent, final float pZoomFactor, final float pAngle);
	}

}
